#include "Gameboard.h"

Gameboard :: Gameboard (Point xy, int w, int h, const string& title)	//initialize all buttons and pictures
	:Touch_window(xy,w,h,title,cb_board),new_game_menu(Point(50,510),50,30,Menu::horizontal,"new"),
	board_last_j(0),board_last_i(0),board_last_p(0),board_last_q(0),
	menu_button(Point(50,510),50,30,"new",cb_menu),
	quit0(Point(521,510),50,30,"quit",cb_quit),
	restart(Point(561,80),50,30,"restart",cb_new),
	undo_button(Point(561,210),50,30,"undo",cb_undo),
	return_button(Point(561,340),50,30,"return",cb_return),
	continue_button(Point(556,285),60,30,"continue",cb_continue),
	quit1(Point(561,470),50,30,"quit",cb_quit) {

		for ( int j = 0; j != 10; ++ j )
			for ( int i = 0; i != 9; ++ i ) {
				board_chess[j][i] = 0;
			}

		board = new Image(Point(0,0),"board.jpg");
		initial = new Image(Point(0,0),"initial.jpg");
		attach(*initial);

		Image* itmp0 = new Image(Point(40,40),"b_win.jpg");
		win_lose.push_back(itmp0);
		Image* itmp1 = new Image(Point(40,40),"r_win.jpg");
		win_lose.push_back(itmp1);

		new_game_menu.attach( new Button(Point(50,510),50,30,"HvsH",cb_HvsH));
		new_game_menu.attach(new Button(Point(100,510),50,30,"HvsR",cb_HvsR));
		new_game_menu.attach(new Button(Point(150,510),50,30,"RvsH",cb_RvsH));
		attach(new_game_menu);
		new_game_menu.hide();
		attach(menu_button);
		attach(quit0);

		undo_reminder = new Image(Point(158,158),"undo_reminder.jpg");

		changed_orig = 0;
		changed_targ = 0;

		redraw();
}

bool Gameboard :: pos_available(int i, int j) {
	if ( board_chess[j][i] == 0 )
		return 0;
	else
		return 1;
}

int Gameboard :: check_clear (int orig_i, int orig_j, int target_i, int target_j) {
	int counter = 0;
	if ( orig_i == target_i && orig_j > target_j ) {
		int diff = orig_j - target_j;
		for ( int m = 1; m != diff; ++ m )
			if ( board_chess[orig_j-m][orig_i] )
				++ counter;
	}
	if ( orig_i == target_i && orig_j < target_j ) {
		int diff = target_j - orig_j;
		for ( int m = 1; m != diff; ++ m )
			if ( board_chess[orig_j+m][orig_i] )
				++ counter;
	}
	if ( orig_j == target_j && orig_i > target_i ) {
		int diff = orig_i - target_i;
		for ( int m = 1; m != diff; ++ m )
			if ( board_chess[orig_j][orig_i-m] )
				++ counter;
	}
	if ( orig_j == target_j && orig_i < target_i ) {
		int diff = target_i - orig_i;
		for ( int m = 1; m != diff; ++ m )
			if ( board_chess[orig_j][orig_i+m] )
				++ counter;
	}
	return counter;
}

string Gameboard :: get_iconname (int i, int j, int col) {
	return board_chess[j][i]->image_name[col][0];
}

void Gameboard :: change_turn () {
	for ( int m = 0; m != 10; ++ m )
		for ( int n = 0; n != 9; ++ n )
			if ( board_chess[m][n] )
				board_chess[m][n]->turn = 1 - board_chess[m][n]->turn;
}

void Gameboard :: cb_menu(Address,Address pw) {
	reference_to<Gameboard>(pw).menu_pressed();
}

void Gameboard :: menu_pressed() {
	menu_button.hide();
	new_game_menu.show();
}

void Gameboard :: cb_return(Address,Address pw) {
	reference_to<Gameboard>(pw).return_initial();
}

void Gameboard :: return_initial() {
	detach(*board);
	detach(restart);
	detach(undo_button);
	detach(return_button);
	detach(quit1);
	for ( int j = 0; j != 10; ++ j )
		for ( int i = 0; i != 9; ++ i )
			if ( board_chess[j][i] )
				detach(*board_chess[j][i]->icon);
	attach(*initial);
	attach(menu_button);
	attach(quit0);
	redraw();
}

void Gameboard :: cb_new(Address,Address pw) {
	reference_to<Gameboard>(pw).new_game_HvsH();
}

void Gameboard :: new_game_HvsH() {	//initialize all chessman
	undo_counter[0] = 0;
	undo_counter[1] = 0;
	
	for ( int j = 0; j != 10; ++ j )
		for ( int i = 0; i != 9; ++ i ) {
			if ( board_chess[j][i] )
				if ( board_chess[j][i]->icon ) {
				detach (*board_chess[j][i]->icon);
				board_chess[j][i] = 0;
				}
		}

	detach(*win_lose[0]);
	detach(*win_lose[1]);
	detach(*initial);
	detach(new_game_menu);
	detach(quit0);
	attach(restart);
	attach(undo_button);
	attach(return_button);
	attach(quit1);
	attach(*board);

	King* b_king = new King(4,9,0);
	board_chess[9][4] = b_king;
	Advisor* b_ad1 = new Advisor(3,9,0);
	board_chess[9][3] = b_ad1;
	Advisor* b_ad2 = new Advisor(5,9,0);
	board_chess[9][5] = b_ad2;
	Elephant* b_ele1 = new Elephant(2,9,0);
	board_chess[9][2] = b_ele1;
	Elephant* b_ele2 = new Elephant(6,9,0);
	board_chess[9][6] = b_ele2;
	Horse* b_hor1 = new Horse(1,9,0);
	board_chess[9][1] = b_hor1;
	Horse* b_hor2 = new Horse(7,9,0);
	board_chess[9][7] = b_hor2;
	Chariot* b_cha1 = new Chariot(0,9,0);
	board_chess[9][0] = b_cha1;
	Chariot* b_cha2 = new Chariot(8,9,0);
	board_chess[9][8] = b_cha2;
	Cannon* b_can1 = new Cannon(1,7,0);
	board_chess[7][1] = b_can1;
	Cannon* b_can2 = new Cannon(7,7,0);
	board_chess[7][7] = b_can2;
	Pawn* b_paw1 = new Pawn(0,6,0);
	board_chess[6][0] = b_paw1;
	Pawn* b_paw2 = new Pawn(2,6,0);
	board_chess[6][2] = b_paw2;
	Pawn* b_paw3 = new Pawn(4,6,0);
	board_chess[6][4] = b_paw3;
	Pawn* b_paw4 = new Pawn(6,6,0);
	board_chess[6][6] = b_paw4;
	Pawn* b_paw5 = new Pawn(8,6,0);
	board_chess[6][8] = b_paw5;

	King* r_king = new King(4,0,1);
	board_chess[0][4] = r_king;
	Advisor* r_ad1 = new Advisor(3,0,1);
	board_chess[0][3] = r_ad1;
	Advisor* r_ad2 = new Advisor(5,0,1);
	board_chess[0][5] = r_ad2;
	Elephant* r_ele1 = new Elephant(2,0,1);
	board_chess[0][2] = r_ele1;
	Elephant* r_ele2 = new Elephant(6,0,1);
	board_chess[0][6] = r_ele2;
	Horse* r_hor1 = new Horse(1,0,1);
	board_chess[0][1] = r_hor1;
	Horse* r_hor2 = new Horse(7,0,1);
	board_chess[0][7] = r_hor2;
	Chariot* r_cha1 = new Chariot(0,0,1);
	board_chess[0][0] = r_cha1;
	Chariot* r_cha2 = new Chariot(8,0,1);
	board_chess[0][8] = r_cha2;
	Cannon* r_can1 = new Cannon(1,2,1);
	board_chess[2][1] = r_can1;
	Cannon* r_can2 = new Cannon(7,2,1);
	board_chess[2][7] = r_can2;
	Pawn* r_paw1 = new Pawn(0,3,1);
	board_chess[3][0] = r_paw1;
	Pawn* r_paw2 = new Pawn(2,3,1);
	board_chess[3][2] = r_paw2;
	Pawn* r_paw3 = new Pawn(4,3,1);
	board_chess[3][4] = r_paw3;
	Pawn* r_paw4 = new Pawn(6,3,1);
	board_chess[3][6] = r_paw4;
	Pawn* r_paw5 = new Pawn(8,3,1);
	board_chess[3][8] = r_paw5;

	for ( int j = 0; j != 10; ++ j )
		for ( int i = 0; i != 9; ++ i )
			if ( board_chess[j][i] )
				attach( *(board_chess[j][i]->icon) );
	redraw();
}

void Gameboard :: cb_undo(Address, Address pw) {
	reference_to<Gameboard>(pw).undo();
}

void Gameboard :: undo() {
	int j = 0;
	int i = 0;
	if ( !undo_counter[changed_orig->color] ) {						//resume the last move
		undo_counter[changed_orig->color] = 1;
		board_chess[board_last_p][board_last_q] = changed_orig;
		board_chess[board_last_p][board_last_q]->choosed = 0;
		board_chess[board_last_p][board_last_q]->cur_i = board_chess[board_last_p][board_last_q]->last_i;
		board_chess[board_last_p][board_last_q]->cur_j = board_chess[board_last_p][board_last_q]->last_j;
		detach(*board_chess[board_last_j][board_last_i]->icon);
		board_chess[board_last_p][board_last_q]->icon = new Image(Point(19+board_chess[board_last_p][board_last_q]->last_i*59,19+board_chess[board_last_p][board_last_q]->last_j*59),board_chess[board_last_p][board_last_q]->image_name[board_chess[board_last_p][board_last_q]->color][0]);
		attach(*board_chess[board_last_p][board_last_q]->icon);
		if ( !changed_targ )
			board_chess[board_last_j][board_last_i] = 0;
		else {
			board_chess[board_last_j][board_last_i] = changed_targ;
			board_chess[board_last_j][board_last_i]->cur_i = board_chess[board_last_j][board_last_i]->last_i;
			board_chess[board_last_j][board_last_i]->cur_j = board_chess[board_last_j][board_last_i]->last_j;
			board_chess[board_last_j][board_last_i]->turn = 1;
			board_chess[board_last_j][board_last_i]->icon = new Image(Point(19+board_chess[board_last_j][board_last_i]->cur_i*59,19+board_chess[board_last_j][board_last_i]->cur_j*59),board_chess[board_last_j][board_last_i]->image_name[board_chess[board_last_j][board_last_i]->color][0]);
			attach(*board_chess[board_last_j][board_last_i]->icon);
		}
		redraw();
		change_turn();
	}
	else {		//no chance to undo, display the reminder
		detach(quit1);
		detach(restart);
		detach(return_button);
		detach(undo_button);
		redraw();
		attach(*undo_reminder);
		attach(continue_button);
	}
}

void Gameboard :: cb_quit(Address, Address pw) {
	reference_to<Gameboard>(pw).quit();
}

void Gameboard :: quit() {
	hide();
}

void Gameboard :: cb_continue(Address, Address pw) {
	reference_to<Gameboard>(pw).disappear();
}

void Gameboard :: disappear() {
	detach(continue_button);
	detach(*undo_reminder);
	attach(quit1);
	attach(restart);
	attach(return_button);
	attach(undo_button);
	redraw();
}

void Gameboard :: cb_HvsH(Address,Address pw) {
	reference_to<Gameboard>(pw).new_game_HvsH();
}

void Gameboard :: cb_HvsR(Address,Address pw) {

}

void Gameboard :: cb_RvsH(Address,Address pw) {

}

void Gameboard :: cb_board(Address pw,Address pos) {
	int i = (reference_to<Point>(pos).x-19)/59;		//map the coordinate to the array
	int j = (reference_to<Point>(pos).y-19)/59;
	cout << i << ',' << j << endl;
	if ( i > 8 || j > 9 )							//click outside the board
		return;
	if ( reference_to<Gameboard>(pw).board_chess[j][i] && reference_to<Gameboard>(pw).board_chess[j][i]->turn == 1 
		&& reference_to<Gameboard>(pw).board_chess[j][i]->choosed == 0 )	
		reference_to<Gameboard>(pw).choose_one(i,j);
	if ( !reference_to<Gameboard>(pw).board_chess[j][i] ) {
		for ( int p = 0; p != 10; ++ p )
			for ( int q = 0; q != 9; ++ q )
				if ( reference_to<Gameboard>(pw).board_chess[p][q] && reference_to<Gameboard>(pw).board_chess[p][q]->choosed == 1) 
					if ( reference_to<Gameboard>(pw).board_chess[p][q]->move_valid(i,j,reference_to<Gameboard>(pw)) )
					reference_to<Gameboard>(pw).move(i,j,p,q);
	}
	if ( reference_to<Gameboard>(pw).board_chess[j][i] && reference_to<Gameboard>(pw).board_chess[j][i]->turn == 0) {
			for ( int p = 0; p != 10; ++ p )
				for ( int q = 0; q != 9; ++ q )
					if ( reference_to<Gameboard>(pw).board_chess[p][q] && reference_to<Gameboard>(pw).board_chess[p][q]->choosed == 1)
							if ( reference_to<Gameboard>(pw).board_chess[p][q]->eat_valid(i,j,reference_to<Gameboard>(pw)) )
								reference_to<Gameboard>(pw).eat(i,j,p,q);
	}				
}

void Gameboard :: choose_one(int i, int j) {
	for ( int p = 0; p != 10; ++ p )
		for ( int q = 0; q != 9; ++ q )
			if ( board_chess[p][q] && board_chess[p][q]->choosed == 1 ) {
				detach(*board_chess[p][q]->icon);
				board_chess[p][q]->choosed = 0;
				board_chess[p][q]->change_icon(board_chess[p][q]->image_name[board_chess[p][q]->color][0]);
				attach(*board_chess[p][q]->icon);
			}
	detach(*board_chess[j][i]->icon);
	board_chess[j][i]->change_icon(board_chess[j][i]->image_name[board_chess[j][i]->color][1]);
	board_chess[j][i]->choosed = 1;
	attach(*board_chess[j][i]->icon);
	redraw();
}

void Gameboard :: move(int i, int j, int p, int q) {
	board_last_j = j;							//store the move
	board_last_i = i;
	board_last_p = p;
	board_last_q = q;
	changed_orig = board_chess[p][q];
	changed_orig->last_i = changed_orig->cur_i;
	changed_orig->last_j = changed_orig->cur_j;
	changed_targ = 0;

	detach(*board_chess[p][q]->icon);
	board_chess[j][i] = board_chess[p][q];
	board_chess[j][i]->cur_i = i;
	board_chess[j][i]->cur_j = j;
	board_chess[j][i]->choosed = 0;
	board_chess[j][i]->icon = new Image(Point(20+i*59,20+j*59),board_chess[j][i]->image_name[board_chess[j][i]->color][0]);
	board_chess[p][q] = 0;
	attach(*board_chess[j][i]->icon);
	redraw();
	change_turn();
}

void Gameboard :: eat(int i, int j, int p, int q) {
	board_last_j = j;							//store the move
	board_last_i = i;
	board_last_p = p;
	board_last_q = q;
	changed_orig = board_chess[p][q];
	changed_orig->last_i = q;
	changed_orig->last_j = p;
	changed_targ = board_chess[j][i];
	changed_targ->last_i = i;
	changed_targ->last_j = j;
	detach(*board_chess[j][i]->icon);
	detach(*board_chess[p][q]->icon);
	string tmp = board_chess[j][i]->image_name[board_chess[j][i]->color][0];	
	board_chess[j][i] = board_chess[p][q];
	board_chess[j][i]->cur_i = i;
	board_chess[j][i]->cur_j = j;
	board_chess[j][i]->choosed = 0;
	board_chess[j][i]->icon = new Image(Point(20+i*59,20+j*59),board_chess[j][i]->image_name[board_chess[j][i]->color][0]);
	board_chess[p][q] = 0;
	attach(*board_chess[j][i]->icon);
	if ( tmp == "b_gong.gif" )					//judge if the game is over
		attach(*win_lose[1]);
	if ( tmp == "r_gong.gif" )
		attach(*win_lose[0]);
	redraw();
	change_turn();
}